package org.subatu.orm.query.condition;


import org.springframework.util.Assert;
import org.subatu.orm.query.base.BaseSql;
import org.subatu.orm.query.base.CondEnum;
import org.subatu.orm.query.brige.ConditionAndBy;
import org.subatu.orm.query.function.FunctionToQueryColumnUtil;
import org.subatu.orm.query.function.SFunction;
import org.subatu.orm.query.table.CondColumn;
import org.subatu.orm.query.table.QueryColumn;
import org.subatu.orm.query.table.TableDef;

import java.util.List;

/**
 * 比较条件
 */
public interface Condition extends BaseSql {

    // ********* 以下是构造 关系条件 *********
    default ConditionAndBy and() {
        return makeCondition(CondEnum.and);
    }

    default ConditionAndBy or() {
        return makeCondition(CondEnum.or);
    }

    default ConditionAndBy boxL() {
        return makeCondition(CondEnum.boxL);
    }

    default ConditionAndBy boxR() {
        return makeCondition(CondEnum.boxR);
    }

    // ********* 以下是构造 对比 条件 *********

    default <E> ConditionAndBy eq(SFunction<E> column, Object value) {
        return eq(true, column, value);
    }

    default <E> ConditionAndBy eq(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.eq, value);
    }

    default <E> ConditionAndBy gt(SFunction<E> column, Object value) {
        return gt(true, column, value);
    }

    default <E> ConditionAndBy gt(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.gt, value);
    }

    default <E> ConditionAndBy ge(SFunction<E> column, Object value) {
        return ge(true, column, value);
    }

    default <E> ConditionAndBy ge(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.ge, value);
    }

    default <E> ConditionAndBy lt(SFunction<E> column, Object value) {
        return lt(true, column, value);
    }

    default <E> ConditionAndBy lt(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.lt, value);
    }

    default <E> ConditionAndBy le(SFunction<E> column, Object value) {
        return le(true, column, value);
    }

    default <E> ConditionAndBy le(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.le, value);
    }

    default <E> ConditionAndBy in(SFunction<E> column, Object value) {
        return in(true, column, value);
    }

    default <E> ConditionAndBy in(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.in, value);
    }

    default <E> ConditionAndBy notIn(SFunction<E> column, Object value) {
        return notIn(true, column, value);
    }

    default <E> ConditionAndBy notIn(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.notIn, value);
    }

    default <E> ConditionAndBy isNull(SFunction<E> column) {
        return makeCondition(true, column, CondEnum.isNull, null);
    }

    default <E> ConditionAndBy notNull(SFunction<E> column) {
        return makeCondition(true, column, CondEnum.notNull, null);
    }

    default <E> ConditionAndBy likeL(SFunction<E> column, Object value) {
        return likeL(true, column, value);
    }

    default <E> ConditionAndBy likeL(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.likeL, value);
    }

    default <E> ConditionAndBy likeR(SFunction<E> column, Object value) {
        return likeR(true, column, value);
    }

    default <E> ConditionAndBy likeR(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.likeR, value);

    }

    default <E> ConditionAndBy like(SFunction<E> column, Object value) {
        return like(true, column, value);
    }

    default <E> ConditionAndBy like(boolean isCheck, SFunction<E> column, Object value) {
        return makeCondition(isCheck, column, CondEnum.like, value);

    }

    // ********* 以下是实际执行 *********

    // 创建 关系队列
    default ConditionAndBy makeCondition(CondEnum relationEnum) {
        // 构造 关系
        CondColumn condColumn = new CondColumn(relationEnum);
        // 加入到条件队列
        this.getCondList().add(condColumn);
        return (ConditionAndBy) this;
    }

    // 创建 查询队列
    default <E> ConditionAndBy makeCondition(boolean isCheck, SFunction<E> function, CondEnum condEnum, Object value) {
        QueryColumn queryColumn = FunctionToQueryColumnUtil.getQueryColumn(function);
        // 构造 查询条件
        CondColumn condColumn = new CondColumn(isCheck, queryColumn, condEnum, value);
        // 加入到条件队列
        this.getCondList().add(condColumn);
        return (ConditionAndBy) this;
    }

    // 获取 查询条件
    default List<CondColumn> getCondList() {
        // 1. where ; 2 having
        if (sqlData().isWhere.flag == 1) {
            return sqlData().whereList;
        } else if (sqlData().isWhere.flag == 2) {
            return sqlData().havingList;
        }
        // 3. 剩下的, 生成的 条件全部加到 joinList
        Assert.notEmpty(sqlData().joinList, "on 条件前,先写 join 相关函数");
        TableDef joinTable = sqlData().joinList.get(sqlData().joinList.size() - 1);
        return joinTable.getJoinConditionList();
    }

}
